package com.sunricher.telinkblemeshlib;

import android.content.Context;
import android.util.Log;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.lang.reflect.Field;

import androidx.annotation.Nullable;

public class MeshOtaFile {

    private String name;
    private int resourceId;
    private String version;
    private int versionCode;

    private MeshOtaFile() {

    }

    private static MeshOtaFile makeWithField(Field field) throws Exception {

        MeshOtaFile otaFile = new MeshOtaFile();
        otaFile.name = field.getName();
        otaFile.resourceId = field.getInt(field);

        String[] components = otaFile.name.split("_");
        if (components.length != 3) {
            return null;
        }

        String versionString = components[2];

//        int value = 0;
//        for (int i = 0; i < versionString.length(); i++) {
//            int index = versionString.length() - i - 1;
//            int charValue = ((int) versionString.charAt(index)) << (i * 8);
//            value |= charValue;
//        }

        // otaFile.versionCode = value;
        otaFile.version = ("V" + versionString.charAt(0) + "." + versionString.charAt(1)).toUpperCase();
        otaFile.versionCode = getVersionCode(otaFile.version);

        Log.i("MeshOtaFile", "make MeshOtaFile "
                + otaFile.name + ", " + otaFile.version + ", " + otaFile.versionCode);

        return otaFile;
    }

    static MeshOtaFile getOtaFile(MeshDeviceType deviceType, String currentFirmware) throws Exception {

        int rawValue1 = deviceType.getRawValue1();
        int rawValue2 = deviceType.getRawValue2();

        if (deviceType.getCategory() == MeshDeviceType.Category.light) {

            if (rawValue2 >= 0x30 && rawValue2 <= 0x36) {
                rawValue2 = 0x30;
            } else if (rawValue2 >= 0x61 && rawValue2 <= 0x66) {
                rawValue2 = 0x61;
            } else if (rawValue2 == 0x39 || rawValue2 == 0x38) {
                rawValue2 = 0x39;
            } else if (rawValue2 == 0x29) {
                rawValue2 = 0x28;
            }
        }
        if (currentFirmware == null || currentFirmware.isEmpty()) {
            return null;
        }
        String[] items = currentFirmware.split("\\.");
        if (items.length < 2) {
            return null;
        }
        String versionPrefix = items[0];
        if (!versionPrefix.contains("V")) {
            return null;
        }
        String versionPrefixString = "_" + versionPrefix.replaceAll("V", "");
        String otaFilePrefix = String.format("ota_%02x%02x", rawValue1, rawValue2) + versionPrefixString;

        Field[] fields = R.raw.class.getFields();
        Field temp = null;
        for (Field field : fields) {
            String fileName = field.getName();
            // If version prefix is V3, return V4 ota file first.
            if (versionPrefix.equals("V3")) {
                String newOtaFilePrefix = String.format("ota_%02x%02x", rawValue1, rawValue2) + "_4";
                if (fileName.contains(newOtaFilePrefix)) {
                    temp = field;
                    break;
                }
            }
            // If version prefix is V6, return V7 ota file first.
            if (versionPrefix.equals("V6")) {
                String newOtaFilePrefix = String.format("ota_%02x%02x", rawValue1, rawValue2) + "_7";
                if (fileName.contains(newOtaFilePrefix)) {
                    temp = field;
                    break;
                }
            }
            if (fileName.contains(otaFilePrefix)) {
                temp = field;
                break;
            }
        }

        if (temp != null) {
            return MeshOtaFile.makeWithField(temp);
        }
        return null;
    }

    private static int getVersionCode(String version) {

        if (version == null) {
            return 0;
        }

        if (version.contains("V")) {

            String valueString = version.replaceFirst("V", "");
            valueString = valueString.replace(".", "").toLowerCase();

            int value = 0;
            for (int i = 0; i < valueString.length(); i++) {
                int index = valueString.length() - i - 1;
                int charValue = ((int) valueString.charAt(index)) << (i * 8);
                value |= charValue;
            }

            return value;
        }
        return 0;
    }

    public String getName() {
        return name;
    }

    public int getResourceId() {
        return resourceId;
    }

    public String getVersion() {
        return version;
    }

    public int getVersionCode() {
        return versionCode;
    }

    byte[] getData(Context context) throws Exception {

        InputStream inputStream = context.getResources().openRawResource(resourceId);
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = -1;
        while ((len = inputStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, len);
        }
        outputStream.close();
        inputStream.close();
        return outputStream.toByteArray();
    }

    @Override
    public boolean equals(@Nullable @org.jetbrains.annotations.Nullable Object obj) {

        if (obj == null) {
            return false;
        }
        if (obj.getClass() != this.getClass()) {
            return false;
        }

        MeshOtaFile other = (MeshOtaFile) obj;
        return name.equals(other.name);
    }

    public boolean isNeedUpdate(String version) {

        return getVersionCode(version) < this.versionCode;
    }
}
